using System.Xml.XPath;
using Microsoft.Security.Application;

namespace AgileDashboard.AppCode
{
    #region Using declarations

    using System;
    using System.Diagnostics;
    using System.Web;
    using System.Web.Caching;


    #endregion

    /// <summary>
    /// DAO for fetching and caching Team Status objects
    /// </summary>
    public class TeamStatusDao : DaoBase
    {

        private const string NoXmlInResponseFromServer = "No xml in response from server while trying to load Team Status for {0}";

        #region Public Methods

        public TeamStatusDao(IDataConnection dataConnection) : base(dataConnection)
        {
        }

        /// <summary>
        /// Gets and caches a TeamStatus object
        /// </summary>
        /// <param name="iterationSchedule">
        /// A valid Version One iteration schedule
        /// </param>
        /// <param name="team">
        /// A valid team name
        /// </param>
        /// <returns>
        /// A TeamStatus object representing team info
        /// </returns>
        public TeamStatus GetTeamStatus(string iterationSchedule, string team)
        {
            string cacheKey = string.Format("{0}_CurrentIteration_{1}_Status", iterationSchedule, team);

            var teamStatus = HttpRuntime.Cache[cacheKey] as TeamStatus;
            if (teamStatus != null)
            {
                return teamStatus;
            }

            teamStatus = GetTeamStatusData(iterationSchedule, team);

            HttpRuntime.Cache.Insert(
                cacheKey, 
                teamStatus, 
                null,
                DateTime.Now.AddMinutes(Properties.Settings.Default.TeamStatusCacheMinutes), 
                Cache.NoSlidingExpiration, 
                GetTeamStatusCacheUpdateCallback);

            return teamStatus;
        }

        #endregion

        // caching callback method
        #region Methods

        private void GetTeamStatusCacheUpdateCallback(
            string key, 
            CacheItemUpdateReason reason, 
            out object expensiveObject, 
            out CacheDependency dependency, 
            out DateTime absoluteExpiration, 
            out TimeSpan slidingExpiration)
        {
            absoluteExpiration = Cache.NoAbsoluteExpiration;
            slidingExpiration = Cache.NoSlidingExpiration;
            dependency = null;
            expensiveObject = null;

            var teamStatus = HttpRuntime.Cache[key] as TeamStatus;

            // for some reason, there isn't a valid object in the cache. Not good.
            // If this is the case, the cache manager will remove the cached object when this callback returns
            if (teamStatus == null)
            {
                return;
            }

            // if there is a valid cached iteration object, replace it with a fresh object
            teamStatus = GetTeamStatusData(teamStatus.IterationSchedule, teamStatus.Name);

            if (teamStatus != null)
            {
                expensiveObject = teamStatus;
                absoluteExpiration = DateTime.Now.AddMinutes(Properties.Settings.Default.TeamStatusCacheMinutes);
                Debug.WriteLine(string.Format("Refreshed cache for key {0}", key));
                if (Log.IsDebugEnabled)
                {
                    Log.DebugFormat("Refreshed cache for key {0}", key);
                }
            }
        }

        private TeamStatus GetTeamStatusData(string iterationSchedule, string teamName)
        {
            if (iterationSchedule == null)
            {
                throw new ArgumentNullException("iterationSchedule");
            }
            if (teamName == null)
            {
                throw new ArgumentNullException("teamName");
            }
            
            var dao = new IterationDao(DataConnection);
            var currentIteration = dao.GetCurrentIterationBySchedule(iterationSchedule, false);
            if (currentIteration == null)
            {
                throw new ApplicationException("currentIteration is null");
            }

            var teamStatus = new TeamStatus();

            var query = string.Format("Team?where=Name='{0}'&sel={1}", Encoder.UrlEncode(teamName), Encoder.UrlEncode(string.Format(string.Join(",", TeamStatus.VersionOneAttributeNameDictionary.Values), currentIteration.Name)));

            var ret = DataConnection.Execute(query);

            if (ret != null && ret.Document != null)
            {
                var assetElem = ret.XPathSelectElement("/Assets/Asset");
                teamStatus.CurrentIterationToDoHours = Util.GetValue<double>(string.Format(TeamStatus.VersionOneAttributeNameDictionary["CurrentIterationToDoHours"], currentIteration.Name), assetElem);
                teamStatus.CurrentIterationCommitmentHours = Util.GetValue<double>(string.Format(TeamStatus.VersionOneAttributeNameDictionary["CurrentIterationCommitmentHours"], currentIteration.Name), assetElem);
                teamStatus.CurrentIterationDoneHours = Util.GetValue<double>(string.Format(TeamStatus.VersionOneAttributeNameDictionary["CurrentIterationDoneHours"], currentIteration.Name), assetElem);
                teamStatus.Name = teamName;
                teamStatus.IterationSchedule = iterationSchedule;
            }
            else
            {
                var msg = string.Format(NoXmlInResponseFromServer, teamName);
                Log.Error(msg);
                throw new ApplicationException(msg);
            }
            return teamStatus;



        }

        #endregion
    }
}